package com.demo.testng;

import java.io.File;
import java.io.IOException;

import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IBundleCoverage;
import org.jacoco.core.tools.ExecFileLoader;
import org.jacoco.report.DirectorySourceFileLocator;
import org.jacoco.report.FileMultiReportOutput;
import org.jacoco.report.IReportVisitor;
import org.jacoco.report.html.HTMLFormatter;

public class CoverageReport {
	
	private String bathPath = CoverageReport.class.getResource("/").getPath();
	private String title;

	private File executionDataFile;
	private File classesDirectory;
	private File sourceDirectory;
	private File reportDirectory;

	private ExecFileLoader execFileLoader;

	/**
	 * Create a new generator based for the given project.
	 * 
	 * @param projectDirectory
	 */
	public void init() {
		this.title = "demo";
		// "D:\\data\\jacoco\\jacoco.exec"
		this.executionDataFile = new File(bathPath, "../../test-output/jacoco.exec");
		// "D:\\gitProject\\jaws-client-demo\\jaws-client-demo-server\\target\\classes"
		this.classesDirectory = new File(bathPath , "../classes");
		System.out.println(classesDirectory.getPath());
		// "D:\\gitProject\\jaws-client-demo\\jaws-client-demo-server\\src\\main\\java"
		this.sourceDirectory = new File(bathPath, "../../src/main/java");
		// "D:\\data\\jacoco\\coveragereport"
		this.reportDirectory = new File(bathPath, "../../test-output/coverage-report");
	}

	/**
	 * Create the report.
	 * 
	 * @throws IOException
	 */
	public void create() throws IOException {

		init();

		// Read the jacoco.exec file. Multiple data files could be merged
		// at this point
		loadExecutionData();

		// Run the structure analyzer on a single class folder to build up
		// the coverage model. The process would be similar if your classes
		// were in a jar file. Typically you would create a bundle for each
		// class folder and each jar you want in your report. If you have
		// more than one bundle you will need to add a grouping node to your
		// report
		final IBundleCoverage bundleCoverage = analyzeStructure();

		createReport(bundleCoverage);

	}

	private void createReport(final IBundleCoverage bundleCoverage) throws IOException {

		if(reportDirectory.exists()){
			reportDirectory.delete();
		}
		// Create a concrete report visitor based on some supplied
		// configuration. In this case we use the defaults
		final HTMLFormatter htmlFormatter = new HTMLFormatter();
		final IReportVisitor visitor = htmlFormatter.createVisitor(new FileMultiReportOutput(reportDirectory));

		// Initialize the report with all of the execution and session
		// information. At this point the report doesn't know about the
		// structure of the report being created
		visitor.visitInfo(execFileLoader.getSessionInfoStore().getInfos(), execFileLoader.getExecutionDataStore().getContents());

		// Populate the report structure with the bundle coverage information.
		// Call visitGroup if you need groups in your report.
		visitor.visitBundle(bundleCoverage, new DirectorySourceFileLocator(sourceDirectory, "utf-8", 4));

		// Signal end of structure information to allow report to write all
		// information out
		visitor.visitEnd();

	}

	private void loadExecutionData() throws IOException {
		execFileLoader = new ExecFileLoader();
		execFileLoader.load(executionDataFile);
	}

	private IBundleCoverage analyzeStructure() throws IOException {
		final CoverageBuilder coverageBuilder = new CoverageBuilder();
		final Analyzer analyzer = new Analyzer(execFileLoader.getExecutionDataStore(), coverageBuilder);

		analyzer.analyzeAll(classesDirectory);

		return coverageBuilder.getBundle(title);
	}

	public static void main(String[] args) {
		CoverageReport report = new CoverageReport();
		try {
			report.create();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
